package com.duubee.btframe.vo.lambda;

import com.duubee.btframe.enums.BtOrder;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.duubee.btframe.utils.BtStringUtil;
import com.duubee.btframe.vo.BtCondition;

import java.lang.invoke.SerializedLambda;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.*;

@SuppressWarnings(value = "all")
public class BtConditionLambda<T> {

    private BtCondition btCondition;


    public BtConditionLambda() {
        this.btCondition = BtCondition.create();
    }

//    /**
//     * 通过实体创建条件构造器
//     * @param object 对象
//     */
//    public BtConditionLambda(Object object){
//    }


    /**
     * 转换条件构造器
     *
     * @param reqMap 原条件
     * @return 新的条件
     */
    public BtConditionLambda<T> reqMapCreate(Map<String, String[]> reqMap) {
        if (reqMap == null) {
            return this;
        }

        this.btCondition = BtCondition.create(reqMap);
        return this;
    }

    /**
     * 删除条件
     *
     * @param key key
     * @param <R> r r
     * @return 新的条件
     */
    public <R> BtConditionLambda<T> removeCondition(BtFunction<T, R> key) {
        this.btCondition.removeCondition(BtConditionLambda.getFieldName(key));
        return this;
    }

    /**
     * 删除条件
     *
     * @param key key
     * @return 新的条件
     */
    public BtConditionLambda<T> removeCondition(String key) {
        this.btCondition.removeCondition(key);
        return this;
    }

    /**
     * 添加条件(saveOrUpdate使用)
     *
     * @param key 实体类属性
     * @param <R> r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> eq(BtFunction<T, R> key) {
        return this.eq(key, null);
    }

    /**
     * 添加条件
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> eq(BtFunction<T, R> key, Object value) {
        this.btCondition.eq(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件
     *
     * @param tableAndKey 实体类和字段
     * @param value       值
     * @param <R>         r r
     * @param <K>         k k
     * @return BtCondition条件构造器对象
     */
    public <K, R> BtConditionLambda<T> eqFk(BtFunction<K, R> tableAndKey, Object value) {
        Map<String, Object> map = BtConditionLambda.getFieldNameAndClass(tableAndKey);
        if (map == null) {
            throw new RuntimeException("null error");
        }
        this.btCondition.eqFk((Class<?>) map.get("class"), map.get("fieldName").toString(), value);
        return this;
    }

    /**
     * 添加条件(不等于)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> ne(BtFunction<T, R> key, Object value) {
        this.btCondition.ne(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(等于null)
     *
     * @param key 实体类属性
     * @param <R> r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> isNull(BtFunction<T, R> key) {
        this.btCondition.isNull(BtConditionLambda.getFieldName(key));
        return this;
    }

    /**
     * 添加条件(不等于null)
     *
     * @param key 实体类属性
     * @param <R> r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> isNotNull(BtFunction<T, R> key) {
        this.btCondition.isNotNull(BtConditionLambda.getFieldName(key));
        return this;
    }

    /**
     * 添加条件(日期范围查询(开始时间))
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> begin(BtFunction<T, R> key, Object value) {
        this.btCondition.begin(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(日期范围查询(结束时间))
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> end(BtFunction<T, R> key, Object value) {
        this.btCondition.end(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(左模糊查询)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> leftLike(BtFunction<T, R> key, Object value) {
        this.btCondition.leftLike(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(右模糊查询)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> rightLike(BtFunction<T, R> key, Object value) {
        this.btCondition.rightLike(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(模糊查询)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> like(BtFunction<T, R> key, Object value) {
        this.btCondition.like(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(not模糊查询)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> notLike(BtFunction<T, R> key, Object value) {
        this.btCondition.notLike(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(大于)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> gt(BtFunction<T, R> key, Object value) {
        this.btCondition.gt(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(小于)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return BtCondition条件构造器对象
     */
    public <R> BtConditionLambda<T> lt(BtFunction<T, R> key, Object value) {
        this.btCondition.lt(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加条件(大于等于)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> gtEq(BtFunction<T, R> key, Object value) {
        this.btCondition.gtEq(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 结果去重
     *
     * @return 条件构造器
     */
    public BtConditionLambda<T> distinct() {
        this.btCondition.distinct();
        return this;
    }

    /**
     * 添加条件(小于等于)
     *
     * @param key   实体类属性
     * @param value 值
     * @param <R>   r r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> ltEq(BtFunction<T, R> key, Object value) {
        this.btCondition.ltEq(BtConditionLambda.getFieldName(key), value);
        return this;
    }

    /**
     * 添加查询今天数据条件
     *
     * @param key 实体类属性
     * @param <R> r r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> toDay(BtFunction<T, R> key) {
        this.btCondition.toDay(BtConditionLambda.getFieldName(key));
        return this;
    }

    /**
     * 添加查询 在某一天的数据
     *
     * @param key  实体类属性
     * @param date 时间 只获取年月日 00:00:00——23:59:59
     * @param <R>  r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> inDay(BtFunction<T, R> key, Date date) {
        this.btCondition.inDay(BtConditionLambda.getFieldName(key), date);
        return this;
    }

    /**
     * 添加条件(in)
     *
     * @param key   实体类属性
     * @param param 条件值
     * @param <R>   r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> in(BtFunction<T, R> key, Object... param) {
        this.btCondition.in(BtConditionLambda.getFieldName(key), param);
        return this;
    }

    /**
     * 添加条件(not in)
     *
     * @param key   实体类属性
     * @param param 条件值
     * @param <R>   r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> notIn(BtFunction<T, R> key, Object... param) {
        this.btCondition.notIn(BtConditionLambda.getFieldName(key), param);
        return this;
    }

    /**
     * 添加or条件
     *
     * @param btConditions 条件集合
     * @param <R>          r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> or(BtCondition... btConditions) {
        this.btCondition.or(btConditions);
        return this;
    }

    /**
     * 添加排序
     *
     * @param tableAndKey 实体类和字段
     * @param btOrder     排序方式
     * @param <R>         r
     * @param <K>         k
     * @return 条件构造器
     */
    public <K, R> BtConditionLambda<T> addOrderFk(BtFunction<K, R> tableAndKey, BtOrder btOrder) {
        Map<String, Object> map = BtConditionLambda.getFieldNameAndClass(tableAndKey);
        if (map == null) {
            throw new RuntimeException("null error");
        }
        this.btCondition.addOrder((Class<?>) map.get("class"), map.get("fieldName").toString(), btOrder);
        return this;

    }

    /**
     * 添加排序
     *
     * @param column  实体类属性
     * @param btOrder 排序方式
     * @param <R>     r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> addOrder(BtFunction<T, R> column, BtOrder btOrder) {
        this.btCondition.addOrder(BtConditionLambda.getFieldName(column), btOrder);
        return this;
    }

    /**
     * 清除排序
     *
     * @return 条件构造器
     */
    public BtConditionLambda<T> clearOrder() {
        this.btCondition.clearOrder();
        return this;
    }

    /**
     * 添加外表分组
     *
     * @param tableAndKey 指定表和字段
     * @param <R>         r
     * @param <K>         k
     * @return 条件构造器
     */
    public <K, R> BtConditionLambda<T> addGroupFk(BtFunction<K, R> tableAndKey) {

        Map<String, Object> map = BtConditionLambda.getFieldNameAndClass(tableAndKey);
        if (map == null) {
            throw new RuntimeException("null error");
        }
        this.btCondition.addGroup((Class<?>) map.get("class"), map.get("fieldName").toString());
        return this;
    }


    /**
     * 添加分组
     *
     * @param column 指定列
     * @param <R>    r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> addGroup(BtFunction<T, R> column) {

        this.btCondition.addGroup(BtConditionLambda.getFieldName(column));
        return this;
    }


    /**
     * 左连接
     *
     * @param tableAndKey 指定表和字段
     * @param mColumn     主表列
     * @param btCondition 条件构造器
     * @param <R>         r
     * @param <K>         k
     * @return 条件构造器
     */
    public <K, R> BtConditionLambda<T> leftJoin(BtFunction<K, R> tableAndKey, String mColumn, BtCondition btCondition) {
        Map<String, Object> map = BtConditionLambda.getFieldNameAndClass(tableAndKey);
        if (map == null) {
            throw new RuntimeException("null error");
        }
        this.btCondition.leftJoin((Class<?>) map.get("class"), map.get("fieldName").toString(), mColumn, btCondition);
        return this;
    }

    /**
     * 右连接
     *
     * @param tableAndKey 实体类和字段
     * @param mColumn     主表列
     * @param btCondition 条件构造器
     * @param <R>         r
     * @param <K>         k
     * @return 条件构造器
     */
    public <K, R> BtConditionLambda<T> rightJoin(BtFunction<K, R> tableAndKey, String mColumn, BtCondition btCondition) {
        Map<String, Object> map = BtConditionLambda.getFieldNameAndClass(tableAndKey);
        if (map == null) {
            throw new RuntimeException("null error");
        }
        this.btCondition.rightJoin((Class<?>) map.get("class"), map.get("fieldName").toString(), mColumn, btCondition);
        return this;
    }

    /**
     * 内连接
     *
     * @param tableAndKey 实体类和字段
     * @param mColumn     主表列
     * @param btCondition 条件构造器
     * @param <R>         r
     * @param <K>         k
     * @return 条件构造器
     */
    public <K, R> BtConditionLambda<T> innerJoin(BtFunction<K, R> tableAndKey, String mColumn, BtCondition btCondition) {
        Map<String, Object> map = BtConditionLambda.getFieldNameAndClass(tableAndKey);
        if (map == null) {
            throw new RuntimeException("null error");
        }
        this.btCondition.innerJoin((Class<?>) map.get("class"), map.get("fieldName").toString(), mColumn, btCondition);
        return this;
    }

    /**
     * 忽略字段
     *
     * @param fieldNames 字段名
     * @param <R>        r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> ignoreField(BtFunction<T, R>... fieldNames) {
        this.btCondition.ignoreField(BtConditionLambda.getFieldNames(fieldNames));
        return this;
    }

    /**
     * 指定字段
     *
     * @param fieldNames 字段名
     * @param <R>        r
     * @return 条件构造器
     */
    public <R> BtConditionLambda<T> assignField(BtFunction<T, R>... fieldNames) {
        this.btCondition.assignField(BtConditionLambda.getFieldNames(fieldNames));
        return this;
    }

    /**
     * 查询逻辑删除
     *
     * @return 条件构造器
     */
    public BtConditionLambda<T> queryLogicDeleted() {
        this.btCondition.queryLogicDeleted();
        return this;
    }

    /**
     * 设置是否查询逻辑删除
     *
     * @param flag 值
     * @return 条件构造器
     */
    public BtConditionLambda<T> setQueryLogicDeleted(boolean flag) {
        this.btCondition.setQueryLogicDeleted(flag);
        return this;
    }

    /**
     * 查询逻辑删除
     *
     * @return 条件构造器
     */
    public boolean getQueryLogicDeleted() {
        return this.btCondition.getQueryLogicDeleted();
    }


    /**
     * 是否存在忽略字段
     *
     * @return 是否存在
     */
    public boolean existsIgnoreField() {
        return this.btCondition.existsIgnoreField();
    }

    /**
     * 是否存在忽略字段
     *
     * @param fieldName 字段名
     * @param <R>       r
     * @return 是否存在
     */
    public <R> boolean existsIgnoreField(BtFunction<T, R> fieldName) {
        return this.btCondition.existsIgnoreField(BtConditionLambda.getFieldName(fieldName));
    }

    /**
     * 是否存在指定字段查询
     *
     * @return 是否存在
     */
    public boolean existsField() {
        return this.btCondition.existsField();
    }

    /**
     * 是否存在指定字段
     *
     * @param fieldName 字段名
     * @param <R>       r
     * @return 是否存在
     */
    public <R> boolean existsField(BtFunction<T, R> fieldName) {
        return this.btCondition.existsField(BtConditionLambda.getFieldName(fieldName));
    }


    /**
     * 获取key集合
     *
     * @return key集合
     */
    public Set<String> keySet() {
        return this.btCondition.keySet();
    }

    /**
     * 取Object值
     *
     * @param key 键
     * @param <R> r
     * @return 对象
     */
    public <R> Object get(BtFunction<T, R> key) {
        return this.btCondition.get(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取String值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> String getString(BtFunction<T, R> key) {
        return this.btCondition.getString(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取Integer值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> Integer getInteger(BtFunction<T, R> key) {
        return this.btCondition.getInteger(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取Long值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> Long getLong(BtFunction<T, R> key) {
        return this.btCondition.getLong(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取BtCondition数组
     *
     * @param key 键
     * @param <R> r
     * @return 条件构造器数组
     */
    public <R> BtCondition[] getBtConditionArr(BtFunction<T, R> key) {
        return this.btCondition.getBtConditionArr(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取JSONObject
     *
     * @param key 键
     * @param <R> r
     * @return JSON对象
     */
    public <R> JSONObject getJSONObject(BtFunction<T, R> key) {
        return this.btCondition.getJSONObject(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取Boolean值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> Boolean getBoolean(BtFunction<T, R> key) {
        return this.btCondition.getBoolean(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取Date值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> Date getDate(BtFunction<T, R> key) {
        return this.btCondition.getDate(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取getSqlDate值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> java.sql.Date getSqlDate(BtFunction<T, R> key) {
        return this.btCondition.getSqlDate(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取Short值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> Short getShort(BtFunction<T, R> key) {
        return this.btCondition.getShort(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取JSONArray值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> JSONArray getJSONArray(BtFunction<T, R> key) {
        return this.btCondition.getJSONArray(BtConditionLambda.getFieldName(key));
    }

    /**
     * 取BigDecimal值
     *
     * @param key 键
     * @param <R> r
     * @return 值
     */
    public <R> BigDecimal getBigDecimal(BtFunction<T, R> key) {
        return this.btCondition.getBigDecimal(BtConditionLambda.getFieldName(key));
    }


    /**
     * 取Object值
     *
     * @param key 键
     * @param <K> k
     * @param <R> r
     * @return 值
     */
    public <K, R> Object getK(String key) {
        return this.btCondition.get(key);
    }

    /**
     * 取String值
     *
     * @param key 键
     * @param <K> k
     * @param <R> r
     * @return 值
     */
    public <K, R> String getString(String key) {
        return this.btCondition.getString(key);
    }

    /**
     * 取Integer值
     *
     * @param key 键
     * @param <K> k
     * @param <R> r
     * @return 值
     */
    public <K, R> Integer getInteger(String key) {
        return this.btCondition.getInteger(key);
    }

    /**
     * 取Long值
     *
     * @param key 键
     * @param <K> k
     * @param <R> r
     * @return 值
     */
    public <K, R> Long getLong(String key) {
        return this.btCondition.getLong(key);
    }

    /**
     * 取BtCondition数组
     *
     * @param key 键
     * @param <K> k
     * @param <R> r
     * @return 值
     */
    public <K, R> BtCondition[] getBtConditionArr(String key) {
        return this.btCondition.getBtConditionArr(key);
    }

    /**
     * 取JSONObject
     *
     * @param key 键
     * @return 值
     */
    public JSONObject getJSONObject(String key) {
        return this.btCondition.getJSONObject(key);
    }

    /**
     * 取Boolean值
     *
     * @param key 键
     * @return 值
     */
    public Boolean getBoolean(String key) {
        return this.btCondition.getBoolean(key);
    }

    /**
     * 取Date值
     *
     * @param key 键
     * @return 值
     */
    public Date getDate(String key) {
        return this.btCondition.getDate(key);
    }

    /**
     * 取getSqlDate值
     *
     * @param key 键
     * @return 值
     */
    public java.sql.Date getSqlDate(String key) {
        return this.btCondition.getSqlDate(key);
    }

    /**
     * 取Short值
     *
     * @param key 键
     * @return 值
     */
    public Short getShort(String key) {
        return this.btCondition.getShort(key);
    }

    /**
     * 取JSONArray值
     *
     * @param key 键
     * @return 值
     */
    public JSONArray getJSONArray(String key) {
        return this.btCondition.getJSONArray(key);
    }

    /**
     * 取BigDecimal值
     *
     * @param key 键
     * @return 值
     */
    public BigDecimal getBigDecimal(String key) {
        return this.btCondition.getBigDecimal(key);
    }


    /**
     * 获取是否去重
     *
     * @return 是否去重
     */
    public boolean getDistinct() {
        return this.btCondition.getDistinct();
    }

    /**
     * 获取条件构造器
     *
     * @return 条件构造器
     */
    public BtCondition getBtCondition() {
        return this.btCondition;
    }

    /**
     * 批量获取字段名
     *
     * @param btFunction btFunction
     * @param <T>        t
     * @param <R>        r
     * @return 字符串数组
     */
    private static <T, R> String[] getFieldNames(BtFunction<T, R>... btFunction) {
        if (btFunction == null) {
            return null;
        }
        List<String> fieldNameList = new ArrayList<>();
        Arrays.stream(btFunction).forEach(fun -> {
            fieldNameList.add(getFieldName(fun));
        });
        return fieldNameList.toArray(new String[]{});
    }

    /**
     * 获取字段名
     *
     * @param btFunction btFunction
     * @param <T>        t
     * @param <R>        r
     * @return 字段名
     */
    private static <T, R> String getFieldName(BtFunction<T, R> btFunction) {
        if (btFunction == null) {
            return null;
        }
        try {
            // 直接调用writeReplace
            Method writeReplace = btFunction.getClass().getDeclaredMethod("writeReplace");
            writeReplace.setAccessible(true);
            //反射调用
            String implMethodName = ((java.lang.invoke.SerializedLambda) writeReplace.invoke(btFunction)).getImplMethodName();
            if (implMethodName.indexOf("get") == 0 && implMethodName.length() > 3) {
                return BtStringUtil.captureStrToLowerCase(implMethodName.substring(3));
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取字段名和类    fieldName    class
     *
     * @param btFunction btFunction
     * @param <T>        t
     * @param <R>        r
     * @return 字段名和类
     */
    private static <T, R> Map<String, Object> getFieldNameAndClass(BtFunction<T, R> btFunction) {
        try {
            // 直接调用writeReplace
            Method writeReplace = btFunction.getClass().getDeclaredMethod("writeReplace");
            writeReplace.setAccessible(true);
            //反射调用
            SerializedLambda serializedLambda = (java.lang.invoke.SerializedLambda) writeReplace.invoke(btFunction);
            String implMethodName = serializedLambda.getImplMethodName();
            if (implMethodName.indexOf("get") == 0 && implMethodName.length() > 3) {
                Map<String, Object> result = new HashMap<>();
                result.put("fieldName", BtStringUtil.captureStrToLowerCase(implMethodName.substring(3)));
                result.put("class", Class.forName(serializedLambda.getImplClass().replace("/", ".")));
                return result;
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

//    private static <T, R> java.lang.invoke.SerializedLambda doSFunction(BtFunction<T, R> func) throws Exception {
//        // 直接调用writeReplace
//        Method writeReplace = func.getClass().getDeclaredMethod("writeReplace");
//        writeReplace.setAccessible(true);
//        //反射调用
//        return (java.lang.invoke.SerializedLambda) writeReplace.invoke(func);
//    }
//
//    public static void main(String[] args) throws Exception {
//        System.out.println(getFieldName(DemoEntity::getUserName));
//        SerializedLambda serializedLambda = doSFunction(DemoEntity::getId);
//        System.out.println("方法名：" + serializedLambda.getImplMethodName());
//        System.out.println(Class.forName(serializedLambda.getImplClass().replace("/",".")));
//        System.out.println("类名：" + serializedLambda.getImplClass());
//        System.out.println("serializedLambda：" + JSONObject.toJSONString(serializedLambda));
//    }

}
